
package com.platform.modules.mall.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.platform.common.exception.BusinessException;
import com.platform.common.utils.*;
import com.platform.modules.mall.dao.MallActivityDao;
import com.platform.modules.mall.dao.MallGoodsToActivityDao;
import com.platform.modules.mall.entity.ActivityStatusResult;
import com.platform.modules.mall.entity.MallActivityEntity;
import com.platform.modules.mall.entity.MallGoodsToActivityEntity;
import com.platform.modules.mall.service.IAssociTagDataChange;
import com.platform.modules.mall.service.MallActivityService;
import com.platform.modules.mall.service.MallGoodsToActivityService;
import com.platform.modules.mall.service.MallShopsToActivityService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 日常活动Service实现类
 *
 * @author
 * @date 2021-08-11 16:21:47
 */
@Service("mallActivityService")
public class MallActivityServiceImpl extends ServiceImpl<MallActivityDao, MallActivityEntity> implements MallActivityService {

    @Resource
    private JedisUtil jedisUtil;
    @Resource
    private MallGoodsToActivityService goodsToActivityService;
    @Resource
    private MallShopsToActivityService shopsToActivityService;
    @Resource
    private IAssociTagDataChange shopsActivityTag;

    @Override
    public void delCache(String id) {
        jedisUtil.del(Constant.ACTIVITY_DETAILS +id);
    }

    @Override
    public void activityDataChange(MallActivityEntity newEntity, String deleteId) {
        if(StringUtils.isNotBlank(deleteId)){
            if(newEntity == null){
                newEntity = new MallActivityEntity();
            }
            newEntity.setId(deleteId);
            newEntity.setIsShow(0);
        }
    }

    @Override
    public ActivityStatusResult getActivityStatus(String id,String goodsId){
        MallActivityEntity activity = this.lambdaQuery()
                .select(
                        MallActivityEntity::getActivityDate,
                        MallActivityEntity::getActivityTime,
                        MallActivityEntity::getGoodsTag,
                        MallActivityEntity::getExtend1,
                        MallActivityEntity::getWhitelistType
                )
                .eq(MallActivityEntity::getId,id)
                .one();
        if(activity == null){
            throw new BusinessException("活动不存在！");
        }
        int index = 0;
        ActivityStatusResult result = new ActivityStatusResult();
        result.setIsStart(false);
        LocalDate[][] dates = JSONObject.parseObject(activity.getActivityDate(),LocalDate[][].class);
        LocalTime[][] times = JSONObject.parseObject(activity.getActivityTime(),LocalTime[][].class);
        final LocalDate nowd = LocalDate.now();
        final LocalTime nowt = LocalTime.now();
        for(int i = 0;i < dates.length;i++){
            LocalDate[] item = dates[i];
            if(nowd.compareTo(item[0]) >= 0 && nowd.compareTo(item[1]) <= 0){
                // 符合条件
                result.setDate(item);
                result.setIsStart(true);
                break;
            }
        }
        if(result.getIsStart()){
            result.setIsStart(false);
            for(int i = index;i < times.length;i++){
                LocalTime[] item = times[i];
                if(nowt.compareTo(item[0]) >= 0 && nowt.compareTo(item[1]) <= 0){
                    // 符合条件
                    result.setTime(item);
                    result.setIsStart(true);
                    index = i;
                    break;
                }
            }
            if(StringUtils.isNotBlank(goodsId)){
                List<MallGoodsToActivityEntity> goodsToActivityList = goodsToActivityService.lambdaQuery()
                        .select(
                                MallGoodsToActivityEntity::getId,
                                MallGoodsToActivityEntity::getDayOfWeek,
                                MallGoodsToActivityEntity::getExpendCount,
                                MallGoodsToActivityEntity::getWhitelistGrade
                        )
                        .eq(MallGoodsToActivityEntity::getActivityId,id)
                        .eq(MallGoodsToActivityEntity::getGoodsId,goodsId)
                        .eq(MallGoodsToActivityEntity::getDayOfWeek,index)
                        .list();
                if(goodsToActivityList == null || goodsToActivityList.isEmpty()){
                    throw new BusinessException("商品未参与当前活动");
                }
                MallGoodsToActivityEntity goodsToActivityEntity = null;
                for(int i = index;i < goodsToActivityList.size();i++){
                    if(goodsToActivityList.get(i).getExpendCount() > 0){
                        goodsToActivityEntity = goodsToActivityList.get(i);
                    }
                }
                if(goodsToActivityEntity == null || goodsToActivityEntity.getExpendCount() <= 0){
                    throw new BusinessException("库存不足！");
                }
                result.setGoodsToActivityId(goodsToActivityEntity.getId());
                result.setGoodsToActivityEntity(goodsToActivityEntity);
            }
        }
        result.setActivityTag(activity.getGoodsTag());
        result.setExtend1(activity.getExtend1());
        result.setWhitelistType(activity.getWhitelistType());
        return result;
    }

    @Override
    public Object getActivityDetails(String id,String goodsId) {
        JSONObject result = null;
        if((result = JSONObject.parseObject(jedisUtil.get(Constant.ACTIVITY_DETAILS +id))) == null){
            synchronized (id.intern()){
                if((result = JSONObject.parseObject(jedisUtil.get(Constant.ACTIVITY_DETAILS+id))) == null){
                    // 下方计算可以考虑使用redis缓存 时长为当天剩余时间
                    MallActivityEntity activity = this.getById(id);
                    if(activity == null){
                        throw new BusinessException("未找到，活动可能已经结束！");
                    }
                    result = new JSONObject();
                    LocalDate[][] dates = JSONObject.parseObject(activity.getActivityDate(),LocalDate[][].class);

                    final LocalDate now = LocalDate.now();
                    LocalDate[] date = null;
                    int index = 0,min = Integer.MAX_VALUE,temp;
                    for(int i = 0;i < dates.length;i++){
                        LocalDate[] item = dates[i];
                        if(now.compareTo(item[0]) >= 0 && now.compareTo(item[1]) <= 0){
                            // 符合条件
                            date = item;
                            break;
                        }
                        temp = -(int)(item[0].toEpochDay() - now.toEpochDay());
                        if(min < 0 && temp < 0){
                            if(Math.abs(min) > Math.abs(temp)){
                                min = temp;
                                index = i;
                            }
                        }else{
                            if(min > temp){
                                min = temp;
                                index = i;
                            }
                        }
                    }
                    // 未找到符合条件的活动时间，则寻找最接近当前的时间
                    if(date == null){
                        date = dates[index];
                        // activitFlag  0 已经结束   1 进行中  2 未开始
                        if(now.compareTo(date[1]) > 0){
                            result.put("activityFlag", 0);
                        }else{
                            result.put("activityFlag", 2);
                        }
                    }else {
                        result.put("activityFlag", 1);
                    }
                    result.put("activityDate", Arrays.stream(date).map(x->x.toString()).collect(Collectors.toList()));
                    result.put("activityTime",activity.getActivityTime());
                    LocalTime[][] times = JSONObject.parseObject(activity.getActivityTime(),LocalTime[][].class);
                    result.put("activitySecond", Arrays.stream(times).map(x->new int[]{x[0].toSecondOfDay(), x[1].toSecondOfDay()}).toArray());

                    // 查询商品详情
                    int timeSize = JSONObject.parseArray(activity.getActivityTime()).size();
                    Map<String,Object> params = new HashMap<>(8);
                    params.put("start",0);
                    params.put("end",timeSize);
                    params.put("activityId",id);
                    List<Map<String,String>> goodsList = ((MallGoodsToActivityDao)goodsToActivityService.getBaseMapper()).getGoodsDetails(params);

                    int expire = 86400 - LocalTime.now().toSecondOfDay();
                    // 库存 存入redis
                    final Map<String,String> stock = new HashMap<>(goodsList.size() + goodsList.size() / 2);
                    // 商品时段下标
                    final Map<String,String> goodsIndex = new HashMap<>(goodsList.size() + goodsList.size() / 2);
                    goodsList.forEach(x->{
                        stock.put(x.get("id"),String.valueOf(x.get("expendCount")));
                        goodsIndex.put(x.get("goodsId"),x.get("dayOfWeek"));
                    });
                    jedisUtil.setMap(Constant.ACTIVITY_DETAILS_STOCK+id,stock,expire);
                    jedisUtil.setMap(Constant.ACTIVITY_GOODS_TIME_INDEX+id,goodsIndex,expire);
                    // 数据格式重排
                    result.put("goodsData", MapUtils.dataFormat(goodsList, "dayOfWeek",timeSize + timeSize / 2));
                    // 缓存到redis
                    jedisUtil.set(Constant.ACTIVITY_DETAILS+id,result.toJSONString(),expire);
                }
            }
        }

        if(StringUtils.isNotBlank(goodsId)){
            // 只返回当前商品的信息
            result.remove("goodsData");
            result.remove("activityTime");
            Integer index = Integer.parseInt(jedisUtil.hget(Constant.ACTIVITY_GOODS_TIME_INDEX+id,goodsId));
            result.put("activitySecond",new JSONArray[]{result.getJSONArray("activitySecond").getJSONArray(index)});
        }

        // 下方不需要缓存
        result.put("nowTime", LocalTime.now().toSecondOfDay());
        // 获取库存  (活动未开始时可以不需要获取,库存会动态变更)
        result.put("stock", jedisUtil.getMap(Constant.ACTIVITY_DETAILS_STOCK+id));
        return result;
    }


    @Override
    public List<MallActivityEntity> queryAll(Map<String, Object> params) {
        return baseMapper.queryAll(params);
    }

    @Override
    public Page queryPage(Map<String, Object> params) {
        //排序
        params.put("sidx", "T.id");
        params.put("asc", false);
        Page<MallActivityEntity> page = new Query<MallActivityEntity>(params).getPage();
        return page.setRecords(baseMapper.selectMallActivityPage(page, params));
    }

    @Override
    public boolean add(MallActivityEntity mallActivity) {
        if(mallActivity.getIsShow() == null){
            mallActivity.setIsShow(0);
        }
        return this.save(mallActivity);
    }

    @Override
    public boolean update(MallActivityEntity mallActivity) {
        MallActivityEntity old = this.getById(mallActivity.getId());
        if(!old.getName().equals(mallActivity.getName()) || !Optional.ofNullable(old.getExtend1()).orElse("").equals(mallActivity.getExtend1())){
            shopsActivityTag.update(mallActivity.getId(),mallActivity);
        }
        if(!old.getIsShow().equals(mallActivity.getIsShow())){
            if(mallActivity.getIsShow().equals(1)){
                List<String> goodsIds = goodsToActivityService.listObjs(new LambdaQueryWrapper<MallGoodsToActivityEntity>()
                        .select(MallGoodsToActivityEntity::getGoodsId)
                        .eq(MallGoodsToActivityEntity::getActivityId,mallActivity.getId()), Object::toString);
                shopsActivityTag.associAdd(mallActivity,goodsIds.stream().toArray(String[]::new));
                List<String> shopsIds = shopsToActivityService.getShopsIdList(mallActivity.getId());
                for(String id : shopsIds){
                    shopsActivityTag.add(id,mallActivity);
                }
            }else{
                shopsActivityTag.delate(mallActivity.getId());
            }
        }
        return this.updateById(mallActivity);
    }

    @Override
    public boolean delete(String id) {
        return this.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatch(String[] ids) {
        return this.removeByIds(Arrays.asList(ids));
    }

    @Override
    public MallActivityEntity getByCode(String code) {
        MallActivityEntity activity = this.lambdaQuery().eq(MallActivityEntity::getActivityCode, code).one();
        return activity;
    }
}
